Repository navigation
fix(net): hot plugging -- a cable or a Wi-Fi network that goes and comes back - #792
Merged
Merged
Conversation
…rk that goes and comes back Found on the bench Pi: a cable pulled and put back never came back, and the board was off its wired network until a reboot. Neither interface followed the network coming and going. Wired (etherusb). The link was read once, at start, and never again, and the driver exited after configuring the interface. A cable pulled left its address on a port that could not carry it -- with the radio on the same subnet the stack kept sending that subnet out of the dead port -- and a cable put back, or plugged in after a boot without one, was never configured. The driver now stays, keeps its control endpoint and polls the link every 2 s (the PHY's BMSR on a LAN78xx, the adapter's OID_GEN_MEDIA_CONNECT_STATUS on RNDIS). Down: the address goes, and its subnet with it, so another interface carries the traffic. Up: DHCP again, the address and the default route back, wired preferred; no answer is asked again at the next poll, never an invented address. A failed control transfer means the adapter itself has gone, and the watcher ends, releasing the endpoint for the next run. The boot-time "no carrier" check now asks an RNDIS adapter too. Wi-Fi (osinit). Three tries to join at boot, then never again: a board that booted away from its network, or before its router was up, had no Wi-Fi until a reboot. The last supplicant is left running -- it re-joins by itself, at a widening interval -- and the address is asked for when it gets there. After a re-join (a new "group key" in the supplicant's log) the old address is dropped and DHCP asked again: the address was asked for once and went stale. QEMU's usb-net never reported its link (media_state fixed at connected), so tests/host/qemu/usbnet-link-status.patch gives it a link_status_changed, and the harness switches the link off and on through QMP and checks the address goes and comes back. The Wi-Fi half has no QEMU model; it needs the board. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FsRUgdQ797dzH667L9i6HK
…een exchanges; one run per adapter Found by pulling the bench Pi's cable on the hot-plug build: - Wi-Fi went off the network with the cable, and came back only when the cable did. A route keeps the interface it last resolved to while that interface's ifcid is unchanged, and ifcid changed only on bind and unbind. The wired and radio interfaces share their network's route (refcounted, Requals), so when the wired one gave up its address the route kept sending the network's traffic out of the dead port. ipifcstale() bumps every interface's ifcid when an address is added or removed, so each route resolves again to an interface that has the address now -- including back to the wired one when it returns. - The cable came back and its DHCP failed, "udp setup failed: address in use", every two seconds. The client port is the machine's, and the radio's lease watchdog held it for the whole lease to renew. It now closes the conversation while it waits and opens it again to renew, rebind, rediscover or release (opensession). - The harness found a second etherusb run for the same adapter refused: the link watcher held the exclusive control endpoint. It opens it for each poll now, and ends when it cannot have it or when its interface is no longer bound to /net/ether0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FsRUgdQ797dzH667L9i6HK
Bumping every interface's ifcid on any address change (ipifcstale) made every cached route resolve again, loopback's included, and the bench harness's network-console checks over 127.0.0.1 failed three runs in three; with it disabled they passed (280/0). What the cable pull needs is narrower: the routes cached on the interface that gave up its address. ipifcremlifc bumps that interface's ifcid alone, and adding an address bumps nothing -- a returning wired port gets its default route back from etherusb, which re-adding resets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FsRUgdQ797dzH667L9i6HK
…ISC-V
The link watcher was etherusb's, for USB adapters (the Pi 3B+'s
LAN78xx). A board whose Ethernet is a kernel driver -- GENET on the
Pi 4, virtio-net on virt and riscvvirt, GEM on PolarFire -- is
configured by etherusb -k once at boot, and its link was never watched.
- etherusb -k starts the same watcher, reading the link from the netif
("link: N" in /net/ether0/stats), which GENET and GEM already keep
from their PHYs. Down: the address goes. Up: DHCP again, the address
and the default route back.
- virtio-net set nif.link to 1 once and never changed it. It now
negotiates VIRTIO_NET_F_STATUS and keeps nif.link from the device's
status, read at start and on a configuration-change interrupt.
The harness checks it on virt, where QEMU's virtio-net reports
set_link without a patch: the address goes when the link does and
comes back, with its default route, when the link does. GENET has no
QEMU model; on a Pi 4 it wants the board.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FsRUgdQ797dzH667L9i6HK
Member
Author
|
Added in 2d061d3: hot plugging over a kernel link driver, so this isn't only the Pi 3B+'s.
The fixes from the earlier commits are in shared code, so they apply to every board: routes follow an address that goes ( QEMU:
🤖 Generated with Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On the bench Pi, a cable pulled and put back never came back. Neither interface followed the network coming and going.
Fixes
etherusb). The link was read once and the driver exited, so a cable pulled kept its address on a dead port, and a cable plugged in later was never configured.os/ip/ipifc.c). A route keeps its resolved interface while that interface'sifcidis unchanged, andifcidchanged only on bind and unbind.ipifcremlifcnow bumps theifcidof the interface that lost the address.appl/lib/dhcpclient.b). The lease watchdog held UDP 68 for the whole lease, so the other interface's DHCP failed withaddress in use.osinit). Before, it made three tries to join at boot and then never again.Evidence
On the board (Pi 3B+, this build), physical tests:
no carrier; ... until a link comes up, Wi-Fi up; wired configured 3 s after the plug, no rebootNot observed on the board:
QEMU:
tests/host/qemu/usbnet-link-status.patchlets QEMU's usb-net report its link, and the harness pulls and restores the link through QMP.ipifcremlifcchange.dhcp_test2/2 under-c0and-c1, including its lease-renewal case.The 48 h soak of this build is running on the board.
🤖 Generated with Claude Code
https://claude.ai/code/session_01FsRUgdQ797dzH667L9i6HK